package com.sanq.product.cab.redis;

import com.sanq.product.cab.locks.ILock;
import com.sanq.product.cab.locks.ILockCallback;
import com.sanq.product.cab.tools.strings.StringUtil;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisCluster;

/**
 * com.sanq.product.cab.redis.RedisLock
 *
 * @author sanq.Yan
 * @date 2020/3/4
 */
public abstract class RedisLock implements ILock {

    protected volatile boolean isOpenExpirationRenewal = true;

    protected void sleepBySecond(int second) {
        try {
            Thread.sleep(second * 1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    protected void scheduleExpirationRenewal(Object obj, String key, String value) {
        new Thread(() -> {
            while (true) {
                String checkAndExpireScript = "if redis.call('get', KEYS[1]) == ARGV[1] then " +
                        "return redis.call('expire',KEYS[1],ARGV[2]) " +
                        "else " +
                        "return 0 end";

                if (obj instanceof Jedis) {
                    ((Jedis) obj).eval(checkAndExpireScript, 1, key, value, JedisPoolService.DEFAULT_SECOND + "");
                } else if (obj instanceof JedisCluster) {
                    ((JedisCluster) obj).eval(checkAndExpireScript, 1, key, value, JedisPoolService.DEFAULT_SECOND + "");
                }
                sleepBySecond(10);
            }
        }).start();
    }

    @Override
    public String getLockKey(String key) {
        return "redis:lock:" + key;
    }

    @Override
    public String getLockValue() {
        return StringUtil.uuid();
    }

    @Override
    public void execute(String key, ILockCallback callback) {
        String lockKey = getLockKey(key);
        String value = getLockValue();

        lock(lockKey, value);
        try {
            callback.callback();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            unLock(lockKey, value);
        }
    }

}
